package com.hss.thread;


  /*
  https://github.com/yangchong211/YCBlogs/blob/master/java/Java%E5%A4%9A%E7%BA%BF%E7%A8%8B/04.Synchronize%E6%B7%B1%E5%85%A5%E8%A7%A3%E6%9E%90.md
  1.synchronized简单介绍
    1.1 简单介绍


        synchronized 是java语言关键字，当它用来修饰一个方法或者一个代码块的时候，能够保证在同一时刻最多只有一个线程执行该段代码。
        synchronized 关键字，它包括两种用法：synchronized 方法和 synchronized 块。

        //同步的方法
        pubilc synchronized void test() {

        }

        //同步代码块上
        public void test() {
             synchronized(obj) {
                  System.out.println("===");
             }
        }
    1.2 可以修饰哪些内容


        修饰一个代码块，被修饰的代码块称为同步语句块，其作用的范围是大括号{}括起来的代码，作用的对象是调用这个代码块的对象；
        修饰一个方法，被修饰的方法称为同步方法，其作用的范围是整个方法，作用的对象是调用这个方法的对象；
        修改一个静态的方法，其作用的范围是整个静态方法，作用的对象是这个类的所有对象；
        修改一个类，其作用的范围是synchronized后面括号括起来的部分，作用主的对象是这个类的所有对象。

    2.synchonized(this)和synchonized(object)区别

        其实并没有很大的区别，synchonized(object)本身就包含synchonized(this)这种情况，使用的场景都是对一个代码块进行加锁，效率比直接在方法名上加synchonized高一些（下面分析），唯一的区别就是对象的不同。
        对synchronized(this)的一些理解
        一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时，一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
        二、然而，当一个线程访问object的一个synchronized(this)同步代码块时，另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
        三、尤其关键的是，当一个线程访问object的一个synchronized(this)同步代码块时，其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
        四、当一个线程访问object的一个synchronized(this)同步代码块时，它就获得了这个object的对象锁。结果，其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。

    3.sychonized method 和 synchonized代码块的效率问题
        使用前者的对象会获取该对象中所有synchonized的锁，也就是其他线程不能访问所有加了synchonized前缀的方法
        （不仅仅只是当前运行的方法)，影响了其他线程多其他同步方法的访问，降低了效率。而后者只对当前代码块加锁，其他的同步方法不受影响。
    4.代码使用案例
    4.1 第一个案例代码
    4.2 第二个案例代码【 同步代码块时】
    4.3 第三个案例代码【 synchronized对象锁 】
    5.结论
    6.Synchronize问题
    6.1 Synchronize作用于方法和静态方法区别
*/
public class SyncTest {

    void demo(){
        Thread01 t01 = new Thread01();
        System.out.println("synchronized 关键字使用 \n" +"--------------------------");
        Thread ta = new Thread(t01,"A");
        Thread tb = new Thread(t01,"B");
        ta.start();
        tb.start();
    }
      /*执行结果：
      synchronized 关键字使用
--------------------------
      B synchronized loop 0
      B synchronized loop 1
      B synchronized loop 2
      A synchronized loop 0
      A synchronized loop 1
      A synchronized loop 2*/
      private class Thread01 implements Runnable{
          @Override
          public void run() {
              synchronized (this) {
                  for(int i=0;i<3;i++){
                      System.out.println(Thread.currentThread().getName()+" synchronized loop "+i);
                  }
              }
          }
      }



     void  demo2(){
        synchronized (this){
            System.out.println("synchronized 关键字使用 \n" +"--------------------------");
            Thread t02A = new Thread(new Runnable() {
                @Override
                public void run() {
                    method01();
                }
            },"A");
            Thread t02B = new Thread(new Runnable() {

                @Override
                public void run() {
                    method02();
                }
            },"B");
            Thread t02C = new Thread(new Runnable() {
                @Override
                public void run() {
                    method3();
                }
            },"C");
            t02A.start();
            t02B.start();
            t02C.start();
        }
      }

 /*     执行结果：
      synchronized 关键字使用
--------------------------
      B:1
      B:2
      B:3
      C:1
      C:2
      C:3
      A:1
      A:2
      A:3*/


      public void method01(){
          synchronized (this) {
              int i=0;
              while(i++ < 3){
                  System.out.println(Thread.currentThread().getName() +":"+ i);
                  try {
                      Thread.sleep(1000);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
          }
      }

      public void method02(){
          //第2种方式:当一个线程访问object的一个synchronized(this)同步代码块时，
          //其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
          synchronized (this) {
              int j=0;
              while(j++ < 3){
                  System.out.println(Thread.currentThread().getName() +":"+ j);
                  try {
                      Thread.sleep(1000);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
          }
      }

      /*
       * 当一个线程访问object的一个synchronized(this)同步代码块时，
       * 它就获得了这个object的对象锁。
       * 结果，其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
       */
      public synchronized void method3(){
          int k=0;
          while(k++ < 3){
              System.out.println(Thread.currentThread().getName() +":"+ k);
              try {
                  Thread.sleep(1000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
      }

//4.3 第三个案例代码【 synchronized对象锁 】
      class InnerObject{
          private void innerMethod01(){
              int i=0;
              while(i++ < 3){
                  System.out.println(Thread.currentThread().getName() +":"+ i);
                  try {
                      Thread.sleep(1000);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
          }

          private void innerMethod02(){
              int j=0;
              while(j++ < 3){
                  System.out.println(Thread.currentThread().getName() +":"+ j);
                  try {
                      Thread.sleep(1000);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
          }
      }

      final InnerObject innerObj = new InnerObject();
      void demo3(){
          System.out.println("synchronized 关键字使用 \n" +"--------------------------");
          Thread t03A = new Thread(new Runnable() {
              @Override
              public void run() {
                  outerMethod01(innerObj);
              }
          },"A");
          Thread t03B = new Thread(new Runnable() {
              @Override
              public void run() {
                  outerMethod02(innerObj);
              }
          },"B");
          t03A.start();
          t03B.start();

      }
      /**
       * 外部类方法1
       */
      private void outerMethod01(InnerObject innerObj){
          synchronized (innerObj) {
              innerObj.innerMethod01();
          }
      }

      /**
       * 外部类方法2
       */
      private void outerMethod02(InnerObject innerObj){
          innerObj.innerMethod02();
      }

//      执行结果：
//      synchronized 关键字使用
//--------------------------
//      A:1
//      B:1
//      B:2
//      A:2
//      B:3
//      A:3
}
